/**
 * 防止弹窗事件穿透的 Composable
 * 解决移动端弹窗滚动时事件穿透到底层页面的问题
 */

import { ref, watch, onUnmounted } from 'vue'

/**
 * 防止弹窗穿透
 * @param {Ref<boolean>} visible - 弹窗显示状态
 * @param {Object} options - 配置选项
 * @returns {Object}
 */
export function usePreventDialogPenetration(visible, options = {}) {
  const {
    lockBody = true,           // 是否锁定 body 滚动
    restoreScroll = true,      // 是否恢复滚动位置
    preventBodyTouch = true    // 是否阻止 body 的 touch 事件
  } = options

  let scrollY = 0
  let touchHandler = null

  /**
   * 锁定 body 滚动
   */
  const lockScroll = () => {
    if (!lockBody) return

    // 记录当前滚动位置
    scrollY = window.scrollY || window.pageYOffset

    // 锁定 body
    const body = document.body
    body.style.position = 'fixed'
    body.style.top = `-${scrollY}px`
    body.style.left = '0'
    body.style.right = '0'
    body.style.width = '100%'
    body.style.overflow = 'hidden'

    // 阻止 body 的 touch 事件（可选）
    if (preventBodyTouch) {
      touchHandler = (e) => {
        if (e.target === body) {
          e.preventDefault()
        }
      }
      body.addEventListener('touchmove', touchHandler, { passive: false })
    }
  }

  /**
   * 解锁 body 滚动
   */
  const unlockScroll = () => {
    if (!lockBody) return

    const body = document.body

    // 移除 touch 事件监听
    if (touchHandler) {
      body.removeEventListener('touchmove', touchHandler)
      touchHandler = null
    }

    // 恢复 body 样式
    body.style.position = ''
    body.style.top = ''
    body.style.left = ''
    body.style.right = ''
    body.style.width = ''
    body.style.overflow = ''

    // 恢复滚动位置
    if (restoreScroll) {
      window.scrollTo(0, scrollY)
    }
  }

  // 监听弹窗状态变化
  const stopWatch = watch(visible, (newVal) => {
    if (newVal) {
      // 延迟执行，确保 DOM 已渲染
      setTimeout(() => {
        lockScroll()
      }, 0)
    } else {
      unlockScroll()
    }
  }, { immediate: false })

  // 组件卸载时清理
  onUnmounted(() => {
    stopWatch()
    if (visible.value) {
      unlockScroll()
    }
  })

  return {
    lockScroll,
    unlockScroll
  }
}

/**
 * 创建防穿透的触摸事件处理器
 * @param {HTMLElement} scrollableElement - 可滚动元素
 * @returns {Object}
 */
export function useTouchPrevention(scrollableElement) {
  let startY = 0
  let startX = 0

  const handleTouchStart = (e) => {
    startY = e.touches[0].clientY
    startX = e.touches[0].clientX
  }

  const handleTouchMove = (e) => {
    if (!scrollableElement) {
      e.preventDefault()
      return
    }

    const touch = e.touches[0]
    const deltaY = touch.clientY - startY
    const deltaX = touch.clientX - startX

    // 检查是否是横向滑动
    if (Math.abs(deltaX) > Math.abs(deltaY)) {
      e.preventDefault()
      return
    }

    const el = scrollableElement
    const { scrollTop, scrollHeight, clientHeight } = el

    // 检查滚动边界
    const isTop = scrollTop === 0
    const isBottom = scrollTop + clientHeight >= scrollHeight - 1

    // 在顶部向下滑动或在底部向上滑动时阻止默认行为
    if ((isTop && deltaY > 0) || (isBottom && deltaY < 0)) {
      e.preventDefault()
    }
  }

  return {
    handleTouchStart,
    handleTouchMove
  }
}

/**
 * 全局防穿透指令
 * 使用方式：v-prevent-penetration
 */
export const vPreventPenetration = {
  mounted(el, binding) {
    const { value = {} } = binding
    const {
      preventDefault = true,
      stopPropagation = false
    } = value

    const handler = (e) => {
      if (preventDefault) {
        e.preventDefault()
      }
      if (stopPropagation) {
        e.stopPropagation()
      }
    }

    el._preventPenetrationHandler = handler
    el.addEventListener('touchmove', handler, { passive: false })
  },

  unmounted(el) {
    if (el._preventPenetrationHandler) {
      el.removeEventListener('touchmove', el._preventPenetrationHandler)
      delete el._preventPenetrationHandler
    }
  }
}

/**
 * 检测是否在可滚动元素内
 * @param {HTMLElement} element - 目标元素
 * @param {string} selector - 可滚动容器选择器
 * @returns {HTMLElement|null}
 */
export function findScrollableParent(element, selector = '.scroll-container') {
  let parent = element.parentElement

  while (parent) {
    if (parent.matches(selector)) {
      return parent
    }

    const { overflowY } = window.getComputedStyle(parent)
    if (overflowY === 'auto' || overflowY === 'scroll') {
      return parent
    }

    parent = parent.parentElement
  }

  return null
}

/**
 * 智能的触摸处理器
 * 自动识别并处理滚动边界
 */
export function createSmartTouchHandler() {
  let startY = 0
  let currentY = 0

  return {
    start: (e) => {
      startY = e.touches[0].clientY
      currentY = startY
    },

    move: (e, scrollElement) => {
      currentY = e.touches[0].clientY
      const deltaY = currentY - startY

      if (!scrollElement) {
        e.preventDefault()
        return false
      }

      const { scrollTop, scrollHeight, clientHeight } = scrollElement

      // 计算是否到达边界
      const isAtTop = scrollTop <= 0
      const isAtBottom = scrollTop + clientHeight >= scrollHeight

      // 在边界且继续滚动时阻止
      if ((isAtTop && deltaY > 0) || (isAtBottom && deltaY < 0)) {
        e.preventDefault()
        return false
      }

      return true
    },

    end: () => {
      startY = 0
      currentY = 0
    }
  }
}

/**
 * 统一的弹窗防穿透解决方案
 * 包含 body 锁定、touch 事件处理等
 */
export function useDialogPenetrationFix(visible, options = {}) {
  const {
    scrollSelector = '.dialog-scroll-area',
    footerSelector = '.dialog-footer',
    enableBodyLock = true,
    enableTouchPrevention = true
  } = options

  let cleanup = null

  // 使用 body 锁定
  const { lockScroll, unlockScroll } = usePreventDialogPenetration(
    visible,
    { lockBody: enableBodyLock }
  )

  // 设置 touch 事件监听
  const setupTouchListeners = () => {
    if (!enableTouchPrevention) return

    const footer = document.querySelector(footerSelector)
    const scrollArea = document.querySelector(scrollSelector)

    if (!footer) return

    const touchHandler = createSmartTouchHandler()

    const handleTouchStart = (e) => {
      touchHandler.start(e)
    }

    const handleTouchMove = (e) => {
      // 如果在底部按钮区域，直接阻止
      if (footer.contains(e.target)) {
        e.preventDefault()
        return
      }

      // 如果在滚动区域，智能处理
      if (scrollArea && scrollArea.contains(e.target)) {
        touchHandler.move(e, scrollArea)
      } else {
        e.preventDefault()
      }
    }

    document.addEventListener('touchstart', handleTouchStart, { passive: false })
    document.addEventListener('touchmove', handleTouchMove, { passive: false })

    cleanup = () => {
      document.removeEventListener('touchstart', handleTouchStart)
      document.removeEventListener('touchmove', handleTouchMove)
    }
  }

  // 清理 touch 事件监听
  const cleanupTouchListeners = () => {
    if (cleanup) {
      cleanup()
      cleanup = null
    }
  }

  // 监听弹窗状态
  watch(visible, (newVal) => {
    if (newVal) {
      setTimeout(() => {
        setupTouchListeners()
      }, 100)
    } else {
      cleanupTouchListeners()
    }
  })

  // 组件卸载时清理
  onUnmounted(() => {
    cleanupTouchListeners()
  })

  return {
    lockScroll,
    unlockScroll,
    setupTouchListeners,
    cleanupTouchListeners
  }
}

export default {
  usePreventDialogPenetration,
  useTouchPrevention,
  useDialogPenetrationFix,
  vPreventPenetration,
  findScrollableParent,
  createSmartTouchHandler
}
